home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol05 / 05 / parallel / par_int.asm next >
Assembly Source File  |  1990-09-01  |  12KB  |  390 lines

  1. -0
  2. Message 205:
  3. From c-rossgr Wed Aug  1 11:32:17 1990
  4. To: ericm joannes
  5. Subject: Listing3
  6. Date: Wed Aug  1 11:32:16 1990
  7.  
  8.  
  9. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  10. ;;;  PAR_INT.ASM -     Parallel Printer Port By Interrupts
  11. ;;;
  12. ;;;  Copyright 1990 by Ross M. Greenberg
  13. ;;;        for Microsoft Systems Journal
  14. ;;;
  15. ;;;  This program demonstrates the ability to communicate between
  16. ;;;  two PCs via the parallel printer port.  In order for this
  17. ;;;  program to work, a cable must be constructed that has the
  18. ;;;  following pinouts:
  19. ;;;
  20. ;;;     1 ----------  1  - Common Ground
  21. ;;;     2 ---------- 15  \
  22. ;;;     3 ---------- 13   \
  23. ;;;     4 ---------- 12    > Data Out
  24. ;;;     5 ---------- 10   /
  25. ;;;     6 ---------- 11  /
  26. ;;;    10 ----------  5  \
  27. ;;;    11 ----------  6   \
  28. ;;;    12 ----------  4    > Data In
  29. ;;;    13 ----------  3   /
  30. ;;;    15 ----------  2  /
  31. ;;;
  32. ;;;  A copy of the program should be running on each side of the
  33. ;;;  cable. Once running, type whatever you like, then enter an '!'
  34. ;;;  to send the data queued up to the remote machine.  To exit,
  35. ;;;  type a '\'.  Do not control-C out of the program: vectors
  36. ;;;  are not restored nor are interrupts turned off.  You'll likely
  37. ;;;  crash badly.
  38. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  39.  
  40.  
  41. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  42. ;;;
  43. ;;;  Main routine:
  44. ;;;        Initialize
  45. ;;;        - save the old interrupt 0xf vector address
  46. ;;;        - replace it with a vector to the int_handler
  47. ;;;        - turn on interrupt enable in the parallel port
  48. ;;;        - unmask the printer interrupt in the 8259 mask word
  49. ;;;        - clear any interrupts outstanding on the data port
  50. ;;;
  51. ;;;        Poll
  52. ;;;        - if there's a keyboard hit, process it.
  53. ;;;          - if the key is a '\', then exit after restoring vectors
  54. ;;;            and turning off printer interrupts
  55. ;;;          - if the key is a '!', then get and transmit the first
  56. ;;;                 character, if any, in the transmit buffer
  57. ;;;        - if there are any characters in the receive buffer
  58. ;;;               - fetch the next character and display it
  59. ;;;
  60. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  61.  
  62.  
  63. code segment     para
  64. assume     cs:code
  65.  
  66. TRUE       equ   1
  67. FALSE      equ   0
  68.  
  69. BASE_PORT  equ   03bch       ; change this to your port of
  70.                              ; choice. Look at the word at
  71.                              ; 0040:0008 to determine your
  72.                              ; port(s).  The 03bch value
  73.                              ; indicates that the port is
  74.                              ; set up for a combination display
  75.                              ; and parallel port card.  If you
  76.                              ; have a standard parallel port only
  77.                              ; card, chances are your value
  78.                              ; will be 0378h
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85. start:     mov   ax, 350fh   ;save old 0xf interrupt vector
  86.      int   21h
  87.      mov   cs:[old_vect], es
  88.      mov   cs:[old_vect + 2], bx
  89.  
  90.      push  cs
  91.      pop   ds
  92.      mov   dx, offset int_handler
  93.      mov   ax, 250fh         ;set new vector to cs:int_handler
  94.      int   21h
  95.  
  96.      mov   dx, BASE_PORT + 2 ; turn interrupts on in the printer
  97.      in    al, dx
  98.      or    al, 10h           ; fast instruction, so futz
  99.      jmp   $+2
  100.      out   dx, al
  101.  
  102.      mov   dx, 21h           ; unmask the printer interrupt bit
  103.      in    al, dx
  104.      and   al, 7fh           ; fast instruction, so futz
  105.      jmp   $+2
  106.      out   dx, al
  107.  
  108.  
  109.      mov   dx, BASE_PORT     ; turn off outstanding ints for remote
  110.      mov   al, 00
  111.      out   dx, al
  112.  
  113. poll_lp:
  114.      mov   ah, 0bh           ; key hit?
  115.      int   21h
  116.      cmp   al, 0ffh
  117.      jz    get_keyb          ; yes
  118.  
  119. @@:  push  si                ; any outstanding characters in recbuf?
  120.      mov   si, offset cs:inchar_head
  121.      call  unstuff_char
  122.      pop   si
  123.      jnc   poll_lp           ; no
  124.      mov   dl, al            ; yes
  125.      mov   ah, 2             ;display it
  126.      int   21h
  127.      jmp   @B                ; for every character in buffer
  128.  
  129. get_keyb:
  130.      mov   ah, 1             ; get the key
  131.      int   21h
  132.  
  133.      cmp   al, '\'           ; time to leave?
  134.      jz    exit              ; yes
  135.      cmp   al, '!'           ; time to transmit?
  136.      jnz   @F                ; no
  137.      push  si                ; yes, get first character
  138.      mov   si, offset cs:outchar_head
  139.      call  unstuff_char
  140.      pop   si
  141.      jnc   poll_lp           ; jump if no characters
  142.  
  143.      call  send_byte         ; send the first nybble of first char
  144.      jmp   poll_lp           ; and go back for more.
  145.  
  146. @@:  push  si                ; just stuff the character into buffer
  147.      mov   si, offset cs:outchar_head
  148.      call  stuff_char
  149.      pop   si
  150.      jmp   poll_lp           ; and go back for more
  151.  
  152. exit:
  153.      mov   dx, BASE_PORT + 2 ; turn interrupts off in the printer
  154.      in    al, dx
  155.      and   al, 0efh          ; fast instruction, so futz
  156.      jmp   $+2
  157.      out   dx, al
  158.  
  159.      mov   dx, 21h           ; mask the printer interrupt bit
  160.      in    al, dx
  161.      or    al, 080h          ; fast instruction, so futz
  162.      jmp   $+2
  163.      out   dx, al
  164.  
  165.      mov   ds, cs:[old_vect] ; restore the original interrupt
  166.      mov   dx, cs:[old_vect + 2]
  167.      mov   ax, 250fh
  168.      int   21h
  169.  
  170.      mov   ax, 4c01h         ; and exit
  171.      int   21h
  172.  
  173.  
  174. sending    dw    0           ; flag to indicate in middle of a
  175.                              ; send
  176.  
  177. old_vect   dw    2     dup (0)  ; holds the original interrupt vector
  178.  
  179. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  180. ;;;  Interrupt Handler
  181. ;;;
  182. ;;;  An interrupt can either be the result of an incoming character's
  183. ;;;  first nybble, or the "ACK" of the first nybble by the remote
  184. ;;;  machine in response to the first nybble.
  185. ;;;
  186. ;;;  Receiving an interrupt because of first nybble received:
  187. ;;;        - play bit games to remove the interrupt bit from the
  188. ;;;          nybble, then store the nybble and send an interrupt
  189. ;;;          as an acknowledgement.  Wait for the polarity of the
  190. ;;;          of the interrupt to show a new nybble is available,
  191. ;;;          process that nybble and create a byte.  Add the byte
  192. ;;;          to the receive circular buffer and IRET.
  193. ;;;
  194. ;;;  Receiving an interrupt as ACK of first nybble:
  195. ;;;        - send the second nybble out the port.  If there are more
  196. ;;;          characters in the transmit buffer, send the first nybble
  197. ;;;          of the next character.  Reset from the interrupt and
  198. ;;;          return from interrupt.
  199. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  200.  
  201. int_handler:
  202.      sti                     ; re-enable other interrupt handling
  203.      push  ax
  204.      push  dx
  205.  
  206.      cmp   cs:[sending], FALSE  ; is this an ACK or a first nybble?
  207.      jnz   second_nybble        ; it's an ACK
  208.  
  209.      mov   dx, BASE_PORT + 1 ; first nybble.  Get it
  210.      in    al, dx
  211.  
  212.      rcl   al, 1             ; save the topmost bit in carry
  213.      pushf                   ; save the flags
  214.      shl   al, 1             ; shift the interrupt bit away
  215.      popf                    ; get back the flags
  216.      rcr   al, 1             ; rotate the carry bit back. Voila!
  217.  
  218.      shr   al, 1             ; shift the low nybble low
  219.      shr   al, 1
  220.      shr   al, 1
  221.      shr   al, 1
  222.  
  223.      mov   ah, al            ; save it in ah
  224.      mov   dx, BASE_PORT     ; reset the interrupt: level or edge
  225.      mov   al, 00h           ;   triggered, still needs to be done
  226.      out   dx, al
  227.      jmp   $+2
  228.      mov   al, 08h
  229.      out   dx, al            ; now generate an interrupt
  230.  
  231.      inc   dx                ; now poll for interrupt bit to drop
  232. @@:  in    al, dx
  233.      test  al, 040h          ; wait for int pin to zero out
  234.      jnz   @B
  235.  
  236.      rcl   al, 1             ; got other nybble, process as above
  237.      pushf
  238.      shl   al, 1
  239.      popf
  240.      rcr   al, 1
  241.  
  242.      and   al, 0f0h          ; strip low nybble
  243.      or    al, ah            ; an 'OR' creates character in al
  244.  
  245.      push  si
  246.      mov   si, offset cs:inchar_head
  247.      call  stuff_char        ; save it in circular buffer
  248.      pop   si
  249.  
  250. back:
  251.      mov   dx, 20h           ; non-specific EOI
  252.      mov   al, 20h
  253.      out   dx, al
  254.      pop   dx
  255.      pop   ax
  256.  
  257.      iret                    ; back to work
  258.  
  259. cur_byte   db    0           ; just a place to save byte
  260.  
  261.  
  262.  
  263. second_nybble:
  264.      mov   dx, BASE_PORT + 1 ;swallow the interrupt
  265.      in    al, dx
  266.      mov   al, cs:[cur_byte] ; retrieve the byte
  267.      rcl   al, 1
  268.      pushf
  269.      shr   al, 1             ; shift right with zero for bit
  270.      popf
  271.      rcr   al, 1             ; get back from carry
  272.      xor   al, 080h          ; reverse the hi bit: hardware is weird
  273.  
  274.      shr   al, 1
  275.      shr   al, 1
  276.      shr   al, 1
  277.  
  278.      mov   dx, BASE_PORT
  279.      out   dx, al            ; send byte
  280.      dec   cs:[sending]      ; done sending
  281.  
  282.      push  si                ; any more characters to send?
  283.      mov   si, offset cs:outchar_head
  284.      call  unstuff_char
  285.      pop   si
  286.      jnc   back              ; no
  287.  
  288.      call  send_byte         ; yes.  Send first nybble
  289.  
  290.      jmp   back              ; and reset, then iret
  291.  
  292.  
  293. send_byte:
  294.      inc   cs:[sending]      ; set the flag
  295.      mov   cs:[cur_byte], al ; save the byte
  296.  
  297.      shl   al, 1             ; bring low nybble high
  298.      shl   al, 1
  299.      shl   al, 1
  300.      shl   al, 1
  301.  
  302.      rcl   al, 1             ;low nybble now high
  303.      pushf
  304.      shr   al, 1
  305.      or    al, 080h          ; set the interrupt bit
  306.      popf
  307.      rcr   al, 1
  308.      xor   al, 080h          ; reverse hi bit: hardware is weird
  309.  
  310.      shr   al, 1
  311.      shr   al, 1
  312.      shr   al, 1             ; shift it down to send it.
  313.  
  314.      mov   dx, BASE_PORT
  315.      out   dx, al            ; send it, which generates first
  316.                              ; interrupt on send
  317.  
  318.      ret                     ; back to work
  319.  
  320.  
  321. BUFSIZE    equ   1024
  322.  
  323. outchar_head     dw    outchar_buf       ; ptr to head of buffer
  324. outchar_tail     dw    outchar_buf       ; ptr to tail of buffer
  325. outchar_end      dw    outchar_finish    ; lazy comparison
  326. outchar_buf      db    BUFSIZE dup(0)    ; The buffer itself
  327. outchar_finish   db    0                 ; place holder
  328.  
  329. inchar_head      dw    inchar_buf
  330. inchar_tail      dw    inchar_buf
  331. inchar_end dw    inchar_finish
  332. inchar_buf db    BUFSIZE dup(0)
  333. inchar_finish    db    0
  334.  
  335. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  336. ;;;
  337. ;;;  These routines either remove a character if there is one
  338. ;;;  available in the appropriate circular buffer (unstuff_char), or
  339. ;;;  place a character in the appropriate circular buffer.  Have SI
  340. ;;;  point to the head pointer for a given buffer.
  341. ;;;
  342. ;;;  stuff_char:   saves the character in al
  343. ;;;  unstuff_char: retrieves a character and returns with it in AL
  344. ;;;
  345. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  346.  
  347. unstuff_char:
  348.      push  bx
  349.      mov   bx, cs:[si + 2]   ; get the tail pointer
  350.      cmp   bx, cs:[si + 4]   ; compare it with the end of buffer
  351.      jnz   @F                ; equal?
  352.      mov   bx, si            ; yes. Reset to beginning of buffer
  353.      add   si, 6
  354. @@:  cmp   bx, cs:[si]       ; running up against head pointer?
  355.      jz    @F                ; yes. Ignore. Buffer empty
  356.      inc   bx                ; increment the pointer
  357.      mov   al, cs:[bx]       ; get the character
  358.      mov   cs:[si + 2], bx   ; save the pointer
  359.      stc                     ; carry = character retrieved
  360.      pop   bx
  361.      ret
  362.  
  363. @@:  clc
  364.      pop   bx
  365.      ret
  366.  
  367. stuff_char:
  368.      push  bx
  369.      mov   bx, cs:[si]       ; like above, but head instead of tail
  370.      inc   bx
  371.      cmp   bx, cs:[si + 4]
  372.      jnz   @F
  373.      mov   bx, si
  374.      add   si, 6
  375. @@:  cmp   bx, cs:[si + 2]   ; like above, but tail instead of head
  376.      jz    @F
  377.      mov   cs:[bx], al
  378.      mov   cs:[si], bx
  379.      stc                     ; carry = character written
  380.      pop   bx
  381.      ret
  382. @@:  clc
  383.      pop   bx
  384.      ret
  385.  
  386. code ends
  387.  
  388. end start
  389.  
  390.